/*
 * Copyright (c) 2022, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include "driver/rmt.h"
#include "drv_leds.h"

static Esp32Leds _leds;
// WS2812B timing parameters (in terms of clock cycles for 80 MHz clock)
#define T0H 14  // 0.35us
#define T0L 52  // 0.8us
#define T1H 52  // 0.7us
#define T1L 16  // 0.6us

#define RMT_CHANNEL    RMT_CHANNEL_0
#define GPIO_NUM       48   // Assuming GPIO18 is used for data signal TODO: 根据实际回路调整引脚

void ws2812b_set_colors(const RGB_T *colors, size_t num_colors) {
    rmt_item32_t items[num_colors * 24];  // Each LED has 24 bits
    
    for (size_t i = 0; i < num_colors; i++) {
        for (size_t bit = 0; bit < 24; bit++) {
            uint8_t value = ((uint8_t *) &colors[i])[bit / 8];
            uint8_t mask = 1 << (7 - (bit % 8));

            if (value & mask) {
                items[i * 24 + bit].duration0 = T1H;
                items[i * 24 + bit].level0 = 1;
                items[i * 24 + bit].duration1 = T1L;
                items[i * 24 + bit].level1 = 0;
            } else {
                items[i * 24 + bit].duration0 = T0H;
                items[i * 24 + bit].level0 = 1;
                items[i * 24 + bit].duration1 = T0L;
                items[i * 24 + bit].level1 = 0;
            }
        }
    }

    // Send RMT data
    rmt_write_items(RMT_CHANNEL, items, num_colors * 24, true);
    rmt_wait_tx_done(RMT_CHANNEL, portMAX_DELAY);  // Wait for transmission to complete
}

static const LedsOps _ops = {
    ws2812b_set_colors
};

rmt_config_t config = RMT_DEFAULT_CONFIG_TX((gpio_num_t)GPIO_NUM, RMT_CHANNEL);

void Esp32LedsCreate()
{
        // Configure the RMT peripheral
    config.clk_div = 2;  // Set clock divider to 2 for 80 MHz

    ESP_ERROR_CHECK(rmt_config(&config));
    ESP_ERROR_CHECK(rmt_driver_install(RMT_CHANNEL, 0, 0));
    
    LedsCreate(&_leds.super, "WS2812B", &_ops);
}